/*
 * @Author: yli
 * @Date: 2021-05-02 20:40:37
 * @LastEditors: yli
 * @LastEditTime: 2021-05-03 00:11:21
 * @Description: file content
 */

#include "delay.h"

#include "stm32f4xx.h"

static uint8_t fac_us = 0;  //us延时倍乘数
static uint16_t fac_ms = 0; //ms延时倍乘数

/**初始化延迟函数
 * SYSTICK的时钟固定为HCLK时钟的1/8
 * SYSCLK:系统时钟
 * @description: 
 * 初始化延迟函数
 * @param {*}
 * @return {*}
 */
void delay_init(void)
{
    // SysTick->CTRL &= 0xfffffffb; //bit2清空,选择外部时钟  HCLK/8
    // fac_us = SYSCLK / 8;
    fac_us = 168000000 / 8000000;     // 为系统时钟的 1/8, 单位 MHz
    fac_ms = (uint16_t)fac_us * 1000; // 代表每个 ms 需要的 systick 时钟数
}

/**
 * 延时nms  
 * 注意nms的范围  
 * SysTick->LOAD为24位寄存器,所以,最大延时为:  
 * nms<=0xffffff*8*1000/SYSCLK  
 * SYSCLK单位为Hz,nms单位为ms  
 * 对168M条件下,nms<=798ms
 * 超过这个值，应多次调用 delay_ms 实现
 * @description: 延时nms
 * @param {uint16_t} nms: 对168M条件下,nms<=798ms
 * @return {*}
 */
void delay_xms(uint16_t nms)
{
    if (fac_us == 0 || fac_ms == 0)
    {
        fac_us = 168000000 / 8000000;     // 为系统时钟的 1/8, 单位 MHz
        fac_ms = (uint16_t)fac_us * 1000; // 代表每个 ms 需要的 systick 时钟数
    }
    uint32_t temp;
    SysTick->LOAD = (uint32_t)nms * fac_ms;   //时间加载(SysTick->LOAD为24bit)
    SysTick->VAL = 0x00;                      //清空计数器
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开始倒数
    do
    {
        temp = SysTick->CTRL;
    } while (temp & 0x01 && !(temp & (1 << 16))); //等待时间到达

    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
    SysTick->VAL = 0X00;                       //清空计数器
}

/**
 * 延时nus
 * @description: 
 * 延时nus
 * @param {uint32_t} nus: 要延时的us数
 * @return {*}
 */
void delay_us(uint32_t nus)
{
    uint32_t temp;
    SysTick->LOAD = nus * fac_us;             // 时间加载
    SysTick->VAL = 0x00;                      // 清空计数器
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 开始倒数
    do
    {
        temp = SysTick->CTRL;
    } while ((temp & 0x01) && !(temp & (1 << 16))); // 等待时间到达
    /*temp&0x01，这一句是用来判断 systick 定时器是否还处
	 于开启状态，可以防止 systick 被意外关闭导致的死循环。*/

    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器
    SysTick->VAL = 0X00;                       // 清空计数器
}

/**
 * 具有较长时间的延时
 * @description: 延时 nms
 * @param {uint16_t} nms: 0~65535
 * @return {*}
 */
void delay_ms(uint16_t nms)
{
    uint8_t repeat = nms / 540; //这里用 540,是考虑到某些客户可能超频使用,
    //比如超频到 248M 的时候,delay_xms 最大只能延时 541ms 左右了
    uint16_t remain = nms % 540;
    while (repeat)
    {
        delay_xms(540);
        repeat--;
    }
    if (remain)
        delay_xms(remain);
}
